package com.xiaobawang.knowledge.spider.service.impl;

import com.xiaobawang.knowledge.spider.config.EmailConfig;
import com.xiaobawang.knowledge.spider.config.ForestConfig;
import com.xiaobawang.knowledge.spider.constant.PeopleBankConstant;
import com.xiaobawang.knowledge.spider.exception.BusinessException;
import com.xiaobawang.knowledge.spider.forest.PeopleBankClient;
import com.xiaobawang.knowledge.spider.mapper.PeopleBankItemMapper;
import com.xiaobawang.knowledge.spider.model.dto.EmailDTO;
import com.xiaobawang.knowledge.spider.model.dto.FileHelperDTO;
import com.xiaobawang.knowledge.spider.model.entity.PeopleBankItem;
import com.xiaobawang.knowledge.spider.service.EmailService;
import com.xiaobawang.knowledge.spider.service.PeopleBankItemService;
import com.xiaobawang.knowledge.spider.util.DateUtil;
import com.xiaobawang.knowledge.spider.util.FileUtil;
import jakarta.annotation.Resource;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.jsoup.Jsoup;
import org.jsoup.nodes.Document;
import org.jsoup.nodes.Element;
import org.jsoup.parser.Parser;

import java.io.*;

import org.jsoup.select.Elements;
import org.springframework.stereotype.Service;

import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import static com.xiaobawang.knowledge.spider.constant.PeopleBankConstant.VALID_FILE_TYPE_SET;

/**
 * @author synhard
 * @description TODO
 * @date 2025/6/18 14:17
 * @email songxinhang2023@e-chinalife.com
 * @id 18101119
 * @phone 13001321080
 */
@Service
@Slf4j
public class PeopleBankServiceImpl implements PeopleBankItemService {

    @Resource
    PeopleBankClient peopleBankClient;

    private final PeopleBankItemMapper peopleBankItemMapper;

    private final ForestConfig forestConfig;

    private final EmailConfig emailConfig;

    private final EmailService emailService;

    public PeopleBankServiceImpl(PeopleBankItemMapper peopleBankItemMapper,
                                 ForestConfig forestConfig,
                                 EmailConfig emailConfig,
                                 EmailService emailService) {
        this.peopleBankItemMapper = peopleBankItemMapper;
        this.forestConfig = forestConfig;
        this.emailConfig = emailConfig;
        this.emailService = emailService;
    }

    /**
     * @author synhard
     * @description 爬取人民银行规章
     * @date 2025/6/19 09:32
     * @param
     */
    @Override
    public void getPeopleBankRuleFromWeb() {
        String startUrl = forestConfig.getPeopleBankApi() + "/zhengwugongkai/4081330/4406346/4406348/index.html";
        // 爬取所有列表项
        List<PeopleBankItem> peopleBankItemList = new ArrayList<>();
        parsePeopleBankRuleList(startUrl, peopleBankItemList);
        // 筛选掉数据库中存在的
        List<PeopleBankItem> filtered = this.filterExist(peopleBankItemList);
        // 请求文件的字节数组
        List<byte[]> fileByteArrList = this.getPeopleBankRuleByteArray(filtered);
        // 构造每个产品文件名称
        List<String> fileNameList = this.getPeopleBankRuleName(filtered);
        // 发送邮件
        try {
            List<File> zipParts = FileUtil.splitIntoZipFiles(fileByteArrList, fileNameList, 20 * 1024 * 1024);
            for (int i = 0; i < zipParts.size(); i++) {
                File     part     = zipParts.get(i);
                EmailDTO emailDTO = new EmailDTO();
                emailDTO.setSubject("中国人民银行规章(分卷" + (i + 1) + ")");
                emailDTO.setFile(part);
                emailDTO.setContent("此邮件为分卷压缩包，共" + zipParts.size() + "部分，需全部下载后解压");
                emailDTO.setTo(emailConfig.getSupervisorFileReceiver());
                emailDTO.setFrom(emailConfig.getFrom());
                emailService.sendEmail(emailDTO);
                part.delete();
            }
        } catch (Exception ex) {
            log.error("邮件发送失败", ex);
            throw new BusinessException("邮件发送失败: " + ex.getMessage());
        }
        // 将数据插入数据库中
        if (!filtered.isEmpty()) {
            this.peopleBankItemMapper.insertBatch(filtered);
        }
    }

    /**
     * @param url 规章列表也链接
     * @param results 数据对象集合
     * @author synhard
     * @description 递归爬取下一页的数据
     * @date 2025/6/18 15:34
     */
    private void parsePeopleBankRuleList(String url, List<PeopleBankItem> results) {

        // 解析当前页面的所有表格
        results.addAll(parseRuleDetail(url));
        try {
            // 获取网页内容
            Document doc = Jsoup.connect(url)
                    .timeout(10000)
                    .userAgent("Mozilla/5.0")
                    .get();

            // 查找下一页链接
            Element nextPageLink = doc.select("a[title=下一页]").first();

            if (nextPageLink != null && nextPageLink.hasAttr("onclick")) {
                String nextPageUrl = "http://www.pbc.gov.cn" + nextPageLink.attr("tagname");
                parsePeopleBankRuleList(nextPageUrl, results); // 递归爬取下一页
            }
        } catch (Exception e) {
            log.error(e.getMessage());
            throw new BusinessException(e.getMessage());
        }
    }

    /**
     * @author synhard
     * @description 爬取
     * @date 2025/6/19 09:36
     * @param url 规章详情页链接
     * @return java.util.List<com.xiaobawang.knowledge.spider.model.entity.PeopleBankItem>
     */
    private List<PeopleBankItem> parseRuleDetail(String url) {
        try {
            List<PeopleBankItem> pageData = new ArrayList<>();
            Document             doc      = Jsoup.connect(url).get();

            // 定位所有规章表格
            Elements tables = doc.select("table.gz_list");

            for (Element table : tables) {

                // 提取标题
                String title = table.select("p.gz_tit1 a").attr("title");
                if (title.isEmpty()) {
                    title = table.select("p.gz_tit1 a").text();
                }

                // 提取docId
                String[] hrefArray = table.select("p.gz_tit1 a").attr("href").split("/");
                String   docId     = hrefArray[hrefArray.length - 2];

                // 提取发布信息
                String subTitle = table.select("p.gz_tit2").text().replaceAll("^[\\$$\\$$\\s]*", "");

                // 提取DOC下载链接（优先取包含".doc"的链接）
                String   docUrl = "";
                String   pdfUrl = "";
                Elements links  = table.select("a.gz_xz");
                for (Element link : links) {
                    String href = link.attr("href");
                    if (href.contains(".doc")) {
                        docUrl = href;
                    } else if (href.contains(".pdf")) {
                        pdfUrl = href;
                    }
                }

                PeopleBankItem peopleBankItem = new PeopleBankItem();

                String regex = "\\d{4}年\\d{1,2}月\\d{1,2}日";
                Pattern pattern = Pattern.compile(regex);
                Matcher matcher = pattern.matcher(subTitle);
                if (matcher.find()) {
                    String dateStr = matcher.group();
                    Date   date = DateUtil.parseDate(dateStr, DateUtil.DATE_FORMAT_CHINESE);
                    peopleBankItem.setPublishDate(DateUtil.formatDate(date, DateUtil.DATE_FORMAT));
                }
                peopleBankItem.setDocId(docId);
                peopleBankItem.setDocUrl(docUrl);
                peopleBankItem.setPdfUrl(pdfUrl);
                peopleBankItem.setTitle(title);
                peopleBankItem.setSubTitle(subTitle);
                peopleBankItem.setItemId(PeopleBankConstant.ITEM_ID_PEOPLE_BANK_RULES);
                peopleBankItem.setItemName(PeopleBankConstant.ITEM_NAME_PEOPLE_RULES);
                pageData.add(peopleBankItem);
            }
            return pageData;
        } catch (Exception e) {
            log.error(e.getMessage());
            throw new BusinessException(e.getMessage());
        }
    }

    /**
     * @author synhard
     * @description 爬取人民银行行政规范性文件
     * @date 2025/6/19 09:33
     * @param
     */
    @Override
    public void getPeopleBankAdministrationFromWeb() {
        String startUrl = forestConfig.getPeopleBankApi() + "/zhengwugongkai/4081330/4406346/4693545/index.html";
        List<PeopleBankItem> allDocuments = new ArrayList<>();
        // 爬取所有列表页
        this.parsePeopleBankAdministrationList(startUrl, allDocuments);
        // 筛选掉数据库中存在的
        List<PeopleBankItem> filtered = this.filterExist(allDocuments);
        // 请求文件的字节数组
        List<FileHelperDTO> fileHelperDTOList = this.getPeopleBankAdministrationFileByteArray(filtered);
        // 提取字节数组
        List<byte[]> fileByteArrList = new ArrayList<>();
        // 提取文件名称
        List<String> fileNameList = new ArrayList<>();
        for (FileHelperDTO fileHelperDTO : fileHelperDTOList) {
            fileByteArrList.add(fileHelperDTO.getByteArray());
            fileNameList.add(fileHelperDTO.getFileName());
        }
        // 发送邮件
        try {
            List<File> zipParts = FileUtil.splitIntoZipFiles(fileByteArrList, fileNameList, 20 * 1024 * 1024);
            for (int i = 0; i < zipParts.size(); i++) {
                File     part     = zipParts.get(i);
                EmailDTO emailDTO = new EmailDTO();
                emailDTO.setSubject("中国人民银行行政规范性文件(分卷" + (i + 1) + ")");
                emailDTO.setFile(part);
                emailDTO.setContent("此邮件为分卷压缩包，共" + zipParts.size() + "部分，需全部下载后解压");
                emailDTO.setTo(emailConfig.getSupervisorFileReceiver());
                emailDTO.setFrom(emailConfig.getFrom());
                emailService.sendEmail(emailDTO);
                part.delete();
            }
        } catch (Exception ex) {
            log.error("邮件发送失败", ex);
            throw new BusinessException("邮件发送失败: " + ex.getMessage());
        }
        // 将数据插入数据库中
        if (!filtered.isEmpty()) {
            this.peopleBankItemMapper.insertBatch(filtered);
        }
    }

    /**
     * @param url 规章列表也链接
     * @param results 数据对象集合
     * @author synhard
     * @description 递归爬取下一页的数据
     * @date 2025/6/18 15:34
     */
    private void parsePeopleBankAdministrationList(String url, List<PeopleBankItem> results) {
        // 解析当前页面的所有表格
        results.addAll(parsePeopleBankAdministrationDetail(url));
        try {
            // 获取网页内容
            Document doc = Jsoup.connect(url)
                    .timeout(10000)
                    .userAgent("Mozilla/5.0")
                    .get();

            // 查找下一页链接
            Element nextPageLink = doc.select("a[title=下一页]").first();

            if (nextPageLink != null && nextPageLink.hasAttr("onclick")) {
                String nextPageUrl = "http://www.pbc.gov.cn" + nextPageLink.attr("tagname");
                parsePeopleBankAdministrationList(nextPageUrl, results); // 递归爬取下一页
            }
        } catch (Exception e) {
            log.error(e.getMessage());
            throw new BusinessException(e.getMessage());
        }
    }

    private List<PeopleBankItem> parsePeopleBankAdministrationDetail(String url) {
        try {
            List<PeopleBankItem> pageData = new ArrayList<>();
            Document             doc      = Jsoup.connect(url).get();

            // 解析表格数据
            Elements items = doc.select("ul.txtlist > li");
            for (Element item : items) {
                Element link = item.selectFirst("a");
                Element dateSpan = item.selectFirst("span.date");

                if (link != null && dateSpan != null) {
                    String detailUrl = link.attr("href");
                    String fileName = link.attr("title");
                    String publishDate = dateSpan.text();
                    PeopleBankItem peopleBankItem = new PeopleBankItem();
                    String[] detailUrlArray = detailUrl.split("/");
                    String   docId     = detailUrlArray[detailUrlArray.length - 2];
                    peopleBankItem.setDocId(docId);
                    peopleBankItem.setDocUrl(detailUrl);
                    peopleBankItem.setPublishDate(publishDate);
                    peopleBankItem.setTitle(fileName);
                    peopleBankItem.setItemId(PeopleBankConstant.ITEM_ID_PEOPLE_BANK_ADMINISTRATION);
                    peopleBankItem.setItemName(PeopleBankConstant.ITEM_NAME_PEOPLE_ADMINISTRATION);
                    pageData.add(peopleBankItem);
                }
            }
            return pageData;
        } catch (Exception e) {
            log.error(e.getMessage());
            throw new BusinessException(e.getMessage());
        }
    }

    /**
     * @param filtered 过滤后的数据
     * @return java.util.List<java.lang.String>
     * @author synhard
     * @description 获取人民银行规章文件名称
     * @date 2025/6/18 16:42
     */
    private List<String> getPeopleBankRuleName(List<PeopleBankItem> filtered) {
        List<String> fileNameList = new ArrayList<>();
        for (PeopleBankItem peopleBankItem : filtered) {
            String url;
            if (!StringUtils.isBlank(peopleBankItem.getDocUrl())) {
                url = peopleBankItem.getDocUrl();
            } else if (!StringUtils.isBlank(peopleBankItem.getPdfUrl())) {
                url = peopleBankItem.getPdfUrl();
            } else {
                continue;
            }
            String suffix = url.split("\\.")[url.split("\\.").length - 1];
            String prefix = peopleBankItem.getTitle();
            fileNameList.add(prefix + "." + suffix);
        }
        return fileNameList;
    }

    /**
     * @param peopleBankItemList 规章列表
     * @return java.util.List<byte[]>
     * @author synhard
     * @description 获取人民银行规章文件字节数组
     * @date 2025/3/31 17:46
     */
    private List<byte[]> getPeopleBankRuleByteArray(List<PeopleBankItem> peopleBankItemList) {
        List<byte[]> fileByteArrList = new ArrayList<>();
        // 访问每个产品的条款的链接
        for (PeopleBankItem peopleBankItem : peopleBankItemList) {
            // 获取链接，生成文件对应的字节数组
            try {
                String url;
                if (!StringUtils.isBlank(peopleBankItem.getDocUrl())) {
                    url = peopleBankItem.getDocUrl();
                } else if (!StringUtils.isBlank(peopleBankItem.getPdfUrl())) {
                    url = peopleBankItem.getPdfUrl();
                } else {
                    log.error("没有获取到文件链接：{}", peopleBankItem);
                    continue;
                }
                byte[] bytes = this.peopleBankClient.getFileByteArray(url);
                fileByteArrList.add(bytes);
            } catch (Exception ex) {
                log.error(ex.getMessage());
                throw new BusinessException(ex.getMessage());
            }
        }
        return fileByteArrList;
    }

    /**
     * @param peopleBankItemList 规章列表
     * @return java.util.List<byte []>
     * @author synhard
     * @description 获取人民银行规章文件字节数组
     * @date 2025/3/31 17:46
     */
    private List<FileHelperDTO> getPeopleBankAdministrationFileByteArray(List<PeopleBankItem> peopleBankItemList) {
        List<FileHelperDTO> fileHelperDTOList = new ArrayList<>();
        // 访问每个产品的条款的链接
        for (PeopleBankItem peopleBankItem : peopleBankItemList) {
            // 获取链接，生成文件对应的字节数组
            try {
                String url;
                if (!StringUtils.isBlank(peopleBankItem.getDocUrl())) {
                    url = peopleBankItem.getDocUrl();
                } else if (!StringUtils.isBlank(peopleBankItem.getPdfUrl())) {
                    url = peopleBankItem.getPdfUrl();
                } else {
                    log.error("没有获取到文件链接：{}", peopleBankItem);
                    continue;
                }
                String html = this.peopleBankClient.getHtml(url);
                // 尝试将html转成pdf文件
                Document doc = Jsoup.parse(html);
                // 2. 定位class="txt_con"的div
                Element txtConDiv = doc.selectFirst("div.txt_con");
                // 3. 检查是否存在<a>标签并提取href
                Elements links = txtConDiv.select("a");
                // 将原html爬取，转成pdf
                fileHelperDTOList.add(getByteArrFromHtml(peopleBankItem, doc));
                // 将附件链接爬取
                if (!links.isEmpty()) {
                    fileHelperDTOList.addAll(getAttachmentByteArrFromUrl(peopleBankItem, links));
                }
            } catch (Exception ex) {
                log.error(ex.getMessage());
                throw new BusinessException(ex.getMessage());
            }
        }
        return fileHelperDTOList;
    }

    /**
     * @author synhard
     * @description 从html中获取字节数组
     * @date 2025/6/20 15:11
     * @param doc 文档
     * @return byte[]
     */
    private FileHelperDTO getByteArrFromHtml(PeopleBankItem peopleBankItem, Document doc) throws Exception {
        FileHelperDTO res = new FileHelperDTO();
        // 文件内容在html中
        Elements elements = doc.select("." + "content_box");
        Element contentBox = elements.first();
        String normalizedContent = normalizeHtmlWithJsoup(contentBox.outerHtml());
        InputStream inputStream = new ByteArrayInputStream(normalizedContent.getBytes(StandardCharsets.UTF_8));
        OutputStream pdfOutputStream = new FileOutputStream("output.pdf");
        FileUtil.convertToPdf(inputStream, pdfOutputStream);
        File pdfFile = FileUtil.outputStreamToFile(pdfOutputStream, "output.pdf");
        byte[] pdfArr = FileUtil.fileToByteArray(pdfFile);
        pdfFile.delete();
        res.setByteArray(pdfArr);
        res.setFileName("原通知-" + peopleBankItem.getTitle() + ".pdf");
        return res;
    }

    /**
     * @author synhard
     * @description 文档链接中获取byte数组
     * @date 2025/6/20 15:13
     * @return byte[]
     */
    private List<FileHelperDTO> getAttachmentByteArrFromUrl(PeopleBankItem peopleBankItem, Elements links) {
        List<FileHelperDTO> fileHelperDTOList = new ArrayList<>();

        for (Element link : links) {
            String href = link.attr("href");
            if (!href.startsWith("http")) {
                href = this.forestConfig.getPeopleBankApi() + href;
            }
            String suffix = href.split("\\.")[href.split("\\.").length - 1];
            if (!VALID_FILE_TYPE_SET.contains(suffix)) {
                // 不再爬取的有效文件范围内，则跳过
                continue;
            }
            byte[] fileByteArray = this.peopleBankClient.getFileByteArray(href);
            FileHelperDTO fileHelperDTO = new FileHelperDTO();
            String attachmentName = FileUtil.sanitizeFilename(link.text());
            fileHelperDTO.setFileName(peopleBankItem.getTitle() + "-附件-" + attachmentName + "." + suffix);
            fileHelperDTO.setByteArray(fileByteArray);
            fileHelperDTOList.add(fileHelperDTO);
        }
        return fileHelperDTOList;
    }

    /**
     * @author synhard
     * @description 规范化html
     * @date 2025/6/19 16:44
     * @param html
     * @return java.lang.String
     */
    private static String normalizeHtmlWithJsoup(String html) {
        // 使用XML解析器处理
        Document doc = Jsoup.parse(html, "", Parser.xmlParser());

        // 设置XHTML输出格式
        doc.outputSettings()
                .syntax(Document.OutputSettings.Syntax.xml)
                .escapeMode(org.jsoup.nodes.Entities.EscapeMode.xhtml)
                .charset("UTF-8");

        return doc.toString();
    }

    /**
     * @param peopleBankItemList 爬取到的数据
     * @return java.util.List<com.xiaobawang.knowledge.spider.model.entity.GovernmentFinancialItem>
     * @author synhard
     * @description 过滤掉数据库中存在的内容
     * @date 2025/6/9 09:10
     */
    private List<PeopleBankItem> filterExist(List<PeopleBankItem> peopleBankItemList) {
        List<PeopleBankItem> res = new ArrayList<>();
        // 根据 docId 和 itemId 过滤数据
        for (PeopleBankItem item : peopleBankItemList) {
            PeopleBankItem query = new PeopleBankItem();
            query.setDocId(item.getDocId());
            query.setItemId(item.getItemId());
            List<PeopleBankItem> queryResult = this.peopleBankItemMapper.queryAllByLimit(query);
            if (queryResult.isEmpty()) {
                res.add(item);
            }
        }
        return res;
    }

}
